package jaeger

import (
	"encoding/json"
	"fmt"
	"io"
	"io/ioutil"
	"net/http"
	us "net/url"
)

func jaegerTraceId(url, id string, data interface{}) error {
	var (
		err   error
		trace *http.Response
	)

	fmt.Printf("\n\n %v \n\n", fmt.Sprintf("http://%v/api/traces/%v", url, id))

	if trace, err = http.Get(fmt.Sprintf("http://%v/api/traces/%v", url, id)); err != nil {
		return err
	}

	bts, err := ioutil.ReadAll(trace.Body)
	if err != nil {
		return fmt.Errorf("read trace body %v", err)
	}

	ts := make(map[string]interface{})
	if err = json.Unmarshal(bts, &ts); err != nil {
		return fmt.Errorf("decode trace %v", err)
	}

	for _, atr := range ts["data"].([]interface{}) {
		tid := atr.(map[string]interface{})["traceID"]
		data.(map[string]interface{})[tid.(string)] = atr
	}
	return nil
}

func jaegerTracesK8s(url, guid string, limit, start, end int64, data interface{}) error {
	var (
		err                               error
		serviceReq, operateReq, tracesReq *http.Response
		servicsName, operateName          []string
	)

	//fmt.Printf("here , %v", time.Now().Unix())

	if serviceReq, err = http.Get(fmt.Sprintf(`http://%v/api/services`, url)); err != nil {
		return err
	}

	//fmt.Printf("\n\n \v \n\n", fmt.Sprintf(`http://%v/api/services`, url))

	if servicsName, err = decodeServiceNames(serviceReq.Body); err != nil {
		return err
	}

	//fmt.Printf("%v", servicsName)
	//fmt.Printf("%v", servicsName)

	for _, v := range servicsName {
		if operateReq, err = http.Get(fmt.Sprintf(`http://%v/api/services/%v/operations`, url, us.QueryEscape(v))); err != nil {
			return fmt.Errorf("request operate %v", err)
		}

		//fmt.Printf("req: %v", fmt.Sprintf(`http://%v/api/services/%v/operations`, url, us.QueryEscape(v)))

		if operateName, err = decodeOperateNames(operateReq.Body); err != nil {
			return fmt.Errorf("decode operate %v", err)
		}

		for _, op := range operateName {

			u := fmt.Sprintf(`http://%v/api/traces?service=%v&start=%v&end=%v&limit=%v&operation=%v&tags=%%7B"guid"%%3A"%v"%%7D`, url, us.QueryEscape(v), start, end, limit, us.QueryEscape(op), guid)

			//fmt.Printf("\n\n%v\n\n", u)

			if tracesReq, err = http.Get(u); err != nil {
				return fmt.Errorf("request jaeger %v", err)
			}

			bts, err := ioutil.ReadAll(tracesReq.Body)
			if err != nil {
				return fmt.Errorf("read trace body %v", err)
			}

			ts := make(map[string]interface{})

			//fmt.Printf("T: %s\n", bts)

			if err = json.Unmarshal(bts, &ts); err != nil {
				return fmt.Errorf("decode trace %v", err)
			}

			//fmt.Printf("T: %v\n", ts)

			for _, atr := range ts["data"].([]interface{}) {
				tid := atr.(map[string]interface{})["traceID"]
				spans := atr.(map[string]interface{})["spans"]
				drop := false
				onlyDuplicate := true
				if tid == "00037201c75f5c7c" {
					fmt.Printf("\n\n span %v \n\n", spans)
				}

				for _, sp := range spans.([]interface{}) {
					warning := sp.(map[string]interface{})["warnings"]
					if warning != nil {
						if len(warning.([]interface{})) > 1 || warning.([]interface{})[0].(string) != "duplicate span IDs; skipping clock skew adjustment" {
							onlyDuplicate = false
						}
						drop = true
						//fmt.Printf("warning: %v", sp.(map[string]interface{})["warnings"])
					}
				}
				if drop {
					if onlyDuplicate {
						spansOldMap := make(map[string]interface{})
						for _, sp := range spans.([]interface{}) {
							sid := sp.(map[string]interface{})["spanID"].(string)
							if _, ok := spansOldMap[sid]; ok {
								spansOldMap[sid].(map[string]interface{})["warnings"] = nil
							} else {
								spansOldMap[sid] = sp
							}
						}
						spansNew, i := make([]interface{}, len(spansOldMap)), 0
						for _, kv := range spansOldMap {
							spansNew[i] = kv
							i++
						}
						data.(map[string]interface{})[tid.(string)] = atr

					} else {
						continue
					}
				}
				//fmt.Printf("\n\n T: %v \b\b", atr)
				data.(map[string]interface{})[tid.(string)] = atr
			}

			//*data.(*[]interface{}) = append(*data.(*[]interface{}), ts["data"].([]interface{})...)
		}
	}

	return nil
}

func decodeServiceNames(req io.Reader) ([]string, error) {
	var (
		err error
		bts []byte
	)

	if bts, err = ioutil.ReadAll(req); err != nil {
		return nil, err
	}

	var servics = make(map[string]interface{})
	if err := json.Unmarshal(bts, &servics); err != nil {
		return nil, err
	}

	data, ok := servics["data"]
	if !ok {
		return nil, fmt.Errorf("can't find service data")
	}

	var servicsName = make([]string, len(data.([]interface{})))
	for k, v := range servics["data"].([]interface{}) {
		servicsName[k] = v.(string)
	}

	return servicsName, nil
}

func decodeOperateNames(req io.Reader) ([]string, error) {
	var (
		err error
		bts []byte
	)

	if bts, err = ioutil.ReadAll(req); err != nil {
		return nil, err
	}

	var servics = make(map[string]interface{})
	if err = json.Unmarshal(bts, &servics); err != nil {
		return nil, err
	}

	var operateName = make([]string, len(servics["data"].([]interface{})))
	for k, v := range servics["data"].([]interface{}) {
		operateName[k] = v.(string)
	}

	return operateName, nil
}
